/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2015 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = ftp.c                                                         */
/*  NOTE      =                                                               */
/*  DATE      = 2015/03/27 by geyh                                            */
/******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "frmem.h"
#include "frcomm.h"
#include "frlist.h"
#include "frbyte_buffer.h"
#include "frhash2.h"
#include "frreport_comm.h"
#include "frct_comm.h"
#include "frdb_cursor.h"
#include "frexp_comm.h"
#include "ftp.h"

extern void *g_p_apm_context;

/*
*   ftp  私有信息
*/
typedef struct __st_L7session_ftp_private
{
    unsigned long ul_seq;                             /* 序列号，1次req和response时，使用同一个序列号 */
    L4_transaction st_l4_trans;                         /* 数据 */
//    L7_transaction st_l7_trans;                         /* 数据 */
    int i_flag_data_type;                              //1: FRLOGIN_START 2:FRLOGIN_SUCC 3:FRLOGIN_FAIL 4 FRLOGOUT_START 5 FRLOGOUT_END 0 : other
    char *p_header_name;
    Frreport_body_data *p_st_body_data_req;
    Frreport_body_data *p_st_body_data_resp;
    Frlist_header *p_lst_comm;
    Frlist_header *p_lst_req;
    int i_flag_port_cmd;
    char *p_user_name;
    struct timeval st_login_timestamp;
    char arr_session_id[APM_UUID_SIZE];


}L7session_ftp_private;

/*******************************************************************************
*  FUNC     :  ftp私有信息创建
*  ARGS     :  void
*           :
*  RTN      :  NULL                     失败
*           :  p_st_private             成功
*  NOTE     :
*******************************************************************************/
FR_STATIC L7session_ftp_private* __ftp_private_create(void)
{
    L7session_ftp_private *p_st_private = NULL;

    p_st_private = (L7session_ftp_private *)frmalloc(sizeof(L7session_ftp_private));
    if(p_st_private == NULL)
        return NULL;

    memset(p_st_private, 0x00, sizeof(L7session_ftp_private));

    return p_st_private;

}

/*******************************************************************************
*  FUNC     :  私有信息初始化
*  ARGS     :  p_private_session(ftp的私有session数据)
*  RTN      :  FR_SUCC
*  NOTE     :
*******************************************************************************/
FR_STATIC int __ftp_session_reset(void *p_private_session)
{
    L7session_ftp_private *p_st_private = (L7session_ftp_private *)p_private_session;
    if(p_st_private)
    {
        if(p_st_private->p_st_body_data_req)
            frreport_body_free(&p_st_private->p_st_body_data_req);

        if(p_st_private->p_st_body_data_resp)
            frreport_body_free(&p_st_private->p_st_body_data_resp);

        if(p_st_private->p_lst_req)
            frreport_body_l7list_free(&p_st_private->p_lst_req);

        if(p_st_private->p_lst_comm)
            frreport_body_l7list_free(&p_st_private->p_lst_comm);

        if(p_st_private->p_header_name)
        {
            frfree(p_st_private->p_header_name);
            p_st_private->p_header_name = NULL;
        }

        memset(&p_st_private->st_l4_trans, 0x00, sizeof(L4_transaction));
        p_st_private->i_flag_port_cmd = 0;
        p_st_private->i_flag_data_type = 0;

    }
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  判断是否是ftp
*  ARGS     :  p_st_conn                    输入数据信息
*           :  p_st_packet                 输入数据
*  RTN      :  APM_L7_IS_NO                 不是ftp数据
*           :  APM_L7_IS_YES                是ftp数据
*  NOTE     :
*******************************************************************************/
int ftp_detect(Conntrack *p_st_conn, Apm_packet *p_st_packet)
{
    int i_ret_fun = 0;
    //判断端口是否为21
    if(p_st_packet == NULL || p_st_conn==NULL)
        return APM_L7_IS_NO;

    if(p_st_packet->src_port == 21 || p_st_packet->dst_port == 21)
    {
        i_ret_fun = frct_get_direct_known(p_st_conn);
        if( i_ret_fun == FR_DIRECT_UNKNOWN && p_st_packet->p_payload)
        {
            if(( *p_st_packet->p_payload >= '1' && *p_st_packet->p_payload <= '5')
                || *p_st_packet->p_payload == ' '
              )
                frcap_set_cs_srv(p_st_conn, p_st_packet->src_ip, p_st_packet->src_port);
            else
                frcap_set_cs_srv(p_st_conn, p_st_packet->dst_ip, p_st_packet->dst_port);
        }
        return APM_L7_IS_YES;
    }

    return APM_L7_IS_NO;

}


/*******************************************************************************
*  FUNC     :  ftp数据上报
*  ARGS     :  p_st_conn                    输入数据信息
*           :  i_use_request                ( FR_YES : req数据上报   FR_NO : resp数据上报）
*           :  p_st_hash_report             hash
*           :  p_st_private                 ftp私有数据
*           :  ul_seq
*  RTN      :  FR_SUCC                      成功
*           :  FR_FAIL                      失败
*  NOTE     :
*******************************************************************************/
//FR_STATIC int __ftp_data_format( Conntrack *p_st_conn
//                                , int i_use_request
//                                , Frhash_header *p_st_hash_report
//                                , L7session_ftp_private *p_st_private
//                                , unsigned long ul_seq
//                                , struct timeval *p_st_timestamp)
//{
//    int i_ret = FR_SUCC;
//    Frtrans_info  st_trans_info;
//    L4_transaction *p_st_l4_trans = NULL;
//    L7_transaction *p_st_l7_trans = NULL;
//    Frlist_header *p_st_req_header = NULL;
//    Frlist_header *p_st_resp_header = NULL;
//
//    if(p_st_conn == NULL || p_st_hash_report == NULL || p_st_private == NULL || p_st_timestamp == NULL)
//        return FR_FAIL;
//
//    //st_trans_info数据初始化
//    memset(&st_trans_info,0x00,sizeof(Frtrans_info));
//    p_st_l4_trans = &(st_trans_info.st_l4_trans);
//    p_st_l7_trans = &(st_trans_info.st_l7_trans);
//
//
//    //设置p_st_l4_trans
//    if(i_use_request == FR_YES)
//    {
//        //req数据上报
//        p_st_req_header = frlist_create();
//        if(p_st_req_header == NULL)
//            goto ERROR;
//
//        i_ret = frdb_frlist_copy(&p_st_private->st_req_list,p_st_req_header);
//        if(i_ret == FR_FAIL)
//            goto ERROR;
//
//        //如果是session数据
//        if(p_st_private->i_flag_data_type)
//        {
//            i_ret = frreport_add_session_data(p_st_hash_report
//                                              , p_st_conn
//                                              , p_st_timestamp
//                                              , p_st_req_header
//                                              , p_st_private->i_flag_data_type);
//
//            if(i_ret == FR_FAIL)
//                goto ERROR;
//
//        }
//        else
//        {
//            memcpy(p_st_l4_trans,&p_st_private->st_l4_trans,sizeof(L4_transaction));
//            memcpy(p_st_l7_trans,&p_st_private->st_l7_trans,sizeof(L7_transaction));
//
//            //数据上报
//            i_ret = frreport_add_l7data(p_st_hash_report, p_st_conn, &st_trans_info
//                                        , FR_YES, 1, FR_NO, p_st_req_header, NULL, ul_seq);
//
//            if(i_ret == FR_FAIL)
//                goto ERROR;
//        }
//
//        return i_ret;
//    }
//    else
//    {
//        //resp 数据获取
//        p_st_resp_header = frlist_create();
//        if(p_st_resp_header == NULL)
//            goto ERROR;
//
//        i_ret = frdb_frlist_copy(&p_st_private->st_resp_list,p_st_resp_header);
//        if(i_ret == FR_FAIL)
//            goto ERROR;
//
//        //如果是sess数据
//        if(p_st_private->i_flag_data_type)
//        {
//            i_ret = frreport_add_session_data(p_st_hash_report
//                                              , p_st_conn
//                                              , p_st_timestamp
//                                              , p_st_resp_header
//                                              , p_st_private->i_flag_data_type);
//
//            if(i_ret == FR_FAIL)
//                goto ERROR;
//        }
//        else
//        {
//            //获取数据
//            p_st_req_header = frlist_create();
//            if(p_st_req_header == NULL)
//                goto ERROR;
//
//            i_ret = frdb_frlist_copy(&p_st_private->st_req_list,p_st_req_header);
//            if(i_ret == FR_FAIL)
//                goto ERROR;
//
//            memcpy(p_st_l4_trans,&p_st_private->st_l4_trans,sizeof(L4_transaction));
//            memcpy(p_st_l7_trans,&p_st_private->st_l7_trans,sizeof(L7_transaction));
//
//            i_ret = frreport_add_l7data(p_st_hash_report, p_st_conn, &st_trans_info
//                                        , FR_YES, 1, FR_YES, p_st_req_header, p_st_resp_header, ul_seq);
//
//            if(i_ret == FR_FAIL)
//                goto ERROR;
//        }
//
//        return i_ret;
//    }
//
//ERROR:
//    if(p_st_req_header)
//        frlist_destroy(p_st_req_header,__ftp_data_free);
//
//    if(p_st_resp_header)
//        frlist_destroy(p_st_resp_header,__ftp_data_free);
//
//    return FR_FAIL;
//}



FR_STATIC int __ftp_address_parse(char *p_data, unsigned int ui_data_len, unsigned int *p_ui_ip, unsigned short *p_us_port)
{
    char arr_tmp[64];
    unsigned int ui_ip = 0;
    unsigned short us_port = 0;
    unsigned int ui_len_all = 0, ui_len_tmp = 0;
    int i_index = 0, i_tmp = 0;

    if(p_data == NULL || p_ui_ip == NULL || p_us_port == NULL)
        return FR_FAIL;

    //获取IP
    for(i_index = 0; i_index < 4; )
    {
        if(*p_data == ',')
        {
            i_index++;
            arr_tmp[ui_len_all] = '.';
            ui_len_all++;
            p_data++;
        }
        else
        {
            arr_tmp[ui_len_all] = *p_data;
            ui_len_all++;
            p_data++;
        }

        if(ui_len_all > ui_data_len)
            return FR_FAIL;
    }

    //将最后一位置为'\0'
    arr_tmp[ui_len_all - 1] = '\0';

    ui_ip = iptools_parse_ipaddr(arr_tmp);

    //获取port 首位
    while(*p_data != ',')
    {
        arr_tmp[ui_len_tmp] = *p_data;
        p_data++;
        ui_len_tmp++;
        ui_len_all++;
        if(ui_len_all > ui_data_len)
            return FR_FAIL;
    }

    arr_tmp[ui_len_tmp] = '\0';
    i_tmp = atoi(arr_tmp);


    us_port = i_tmp * 256;

    //跳过','
    p_data++;
    ui_len_all++;

    //获取port 第二位
    if(snprintf(arr_tmp, ui_data_len - ui_len_all + 1, "%s", p_data) == 0)
        return FR_FAIL;

    i_tmp = atoi(arr_tmp);

    us_port += i_tmp;

    *p_ui_ip = ui_ip;
    *p_us_port = us_port;
    return FR_SUCC;

}



/*******************************************************************************
*  FUNC     :  req数据解析
*  ARGS     :  p_data                      req数据
*           :  ui_data_len                 数据长度
*           :  p_st_private                私有数据
*  RTN      :  APM_L7_ANALYZE_SUCC         成功
*           :  APM_L7_ANALYZE_FAIL         失败
*  NOTE     :
*******************************************************************************/
FR_STATIC int __req_parse(char *p_data, unsigned int ui_data_len, L7session_ftp_private *p_st_private, Frreport_body_data *p_st_body_data, Conntrack *p_st_conn)
{
    char *p_name = NULL;
    char *p_value = NULL;
    char *p_pos = NULL;
    unsigned int ui_len_tmp = 0;

    if(p_data == NULL || ui_data_len == 0 || p_st_private == NULL || p_st_body_data == NULL || p_st_conn == NULL)
        return APM_L7_ANALYZE_FAIL;

    //st_req_list
    p_pos = (char *)memchr(p_data, ' ', ui_data_len);

    if(p_pos == NULL)
    {
        p_name = (char *)frmalloc(ui_data_len - 1);
        if(p_name == NULL)
            goto ERROR;

        //去除\r\n
        snprintf(p_name,ui_data_len - 1, "%s", p_data);

        //命令转为大写
        if(frstrupper(p_name, ui_data_len - 2) == FR_FAIL)
            goto ERROR;

        if(strncasecmp(p_name, "QUIT", 4) == 0)
            p_st_private->i_flag_data_type = FRLOGOUT_START;
        //title 命令
        if(frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, p_name) == FR_FAIL)
            goto ERROR;
        frfree(p_name);
        p_name = NULL;

        ui_len_tmp = ui_data_len - 1;
        p_value = (char *)frmalloc(ui_len_tmp);
        if(p_value == NULL)
            goto ERROR;

        snprintf(p_value, ui_len_tmp,"%s",p_data);

        if(frreport_body_l7_add_str(p_st_body_data, "request.ftp.cmd", p_value) == FR_FAIL)
            goto ERROR;
        frfree(p_value);
        p_value = NULL;

        return APM_L7_ANALYZE_SUCC;
    }

    p_pos++;
    ui_len_tmp = p_pos - p_data;
    p_name = (char *)frmalloc(ui_len_tmp);
    if(p_name == NULL)
        goto ERROR;
    snprintf(p_name,ui_len_tmp, "%s", p_data);
    //命令转为大写
    if(frstrupper(p_name, ui_len_tmp - 1) == FR_FAIL)
        goto ERROR;

    if(strncasecmp(p_name, "PASS", 4) == 0)
    {
        frfree(p_name);
        return APM_L7_ANALYZE_TODO;
    }

    if(strncasecmp(p_name, "USER", 4) == 0)
    {
        frfree(p_name);
        p_name = NULL;
        p_st_private->i_flag_data_type = FRLOGIN_START;
        fruuid(p_st_private->arr_session_id);
        if(p_st_private->p_user_name)
            frfree(p_st_private->p_user_name);

        ui_len_tmp = ui_data_len - (p_pos - p_data) - 1;
        p_value = (char *)frmalloc(ui_len_tmp);
        if(p_value == NULL)
            goto ERROR;
        snprintf(p_value,ui_len_tmp,"%s",p_pos);

        p_st_private->p_user_name = p_value;
        p_value = NULL;

        p_st_private->st_login_timestamp.tv_sec = p_st_private->st_l4_trans.st_request_time_first_byte.tv_sec;
        p_st_private->st_login_timestamp.tv_usec = p_st_private->st_l4_trans.st_request_time_first_byte.tv_usec;

        if(frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, "USER") == FR_FAIL)
            goto ERROR;

        return APM_L7_ANALYZE_SUCC;
    }
    else if(strncasecmp(p_name, "PORT", 4) == 0)
    {
        p_st_private->i_flag_port_cmd = 1;
    }
    else if(strncasecmp(p_data, "QUIT", 4) == 0)
    {
        p_st_private->i_flag_data_type = FRLOGOUT_START;
    }
    if(frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_TRANS_TITLE, p_name) == FR_FAIL)
        goto ERROR;
    frfree(p_name);
    p_name = NULL;

    //后移一位、\r\n
    ui_len_tmp = ui_data_len - 1;
    p_value = (char *)frmalloc(ui_len_tmp);
    if(p_value == NULL)
        goto ERROR;

    snprintf(p_value, ui_len_tmp,"%s",p_data);

    if(frreport_body_l7_add_str(p_st_body_data, "request.ftp.cmd", p_value) == FR_FAIL)
        goto ERROR;
    frfree(p_value);
    p_value = NULL;

    return APM_L7_ANALYZE_SUCC;

ERROR:
    if(p_name)
        frfree(p_name);
    if(p_value)
        frfree(p_value);

    return APM_L7_ANALYZE_FAIL;

}


FR_STATIC int __ftp_get_addr(char *p_data, char *p_addr)
{
    char *p_pos1 = NULL, *p_pos2 = NULL;
    int i_tmp = 0;

    if(p_data == NULL || p_addr == NULL)
        return FR_FAIL;

    p_pos1 = strchr(p_data, '(');
    if(p_pos1 == NULL)
        return FR_FAIL;
    p_pos1++;

    p_pos2 = strchr(p_data, ')');
    if(p_pos2 == NULL)
        return FR_FAIL;

    i_tmp = (int)(p_pos2 - p_pos1 + 1);

    snprintf(p_addr, (unsigned int)i_tmp, "%s", p_pos1);

    return FR_SUCC;

}

/*******************************************************************************
*  FUNC     :  resp数据解析
*  ARGS     :  p_data                      req数据
*           :  ui_data_len                 数据长度
*           :  p_st_private                私有数据
*  RTN      :  APM_L7_ANALYZE_SUCC         成功
*           :  APM_L7_ANALYZE_TODO         数据未结束
*           :  APM_L7_ANALYZE_FAIL         失败
*  NOTE     :
*******************************************************************************/
FR_STATIC int __resp_parse(char *p_data, unsigned int ui_data_len, L7session_ftp_private *p_st_private, Frreport_body_data *p_st_body_data, Conntrack *p_st_conn)
{
    char *p_header_value = NULL;
    char *p_response_code_str = NULL;
    unsigned int ui_len_tmp = 0, ui_ip = 0;
    unsigned short us_port = 0;
    int i_ret = APM_L7_ANALYZE_SUCC;
    char arr_code[4];
    char arr_tmp[64];
    long l_response_code = 0;

    if(p_data == NULL || ui_data_len == 0 || p_st_private == NULL || p_st_body_data == NULL || p_st_conn == NULL)
        return APM_L7_ANALYZE_FAIL;

    /* 1:前三数字<SP>/-[内容]\r\n */
    /* 2:<SP>[内容]\r\n */
    /* 空格开头至少有<SP>[]\r\n, 数字开头至少有[三个数字]<SP>[]\r\n */
    if (ui_data_len < 2
        || *(p_data + ui_data_len - 2) != '\r' || *(p_data + ui_data_len - 1) != '\n'
        || (*p_data == ' ' && ui_data_len < 3)
        || (ui_data_len < 6))
    {
        return APM_L7_ANALYZE_FAIL;
    }

    /* 解析 */
    if (*p_data == ' ')
    {
        if(p_st_private->p_header_name)
        {
            snprintf(arr_tmp, sizeof(arr_tmp), "%s End", p_st_private->p_header_name);
            if(strstr(p_data, arr_tmp))
                return APM_L7_ANALYZE_SUCC;
        }
        i_ret = APM_L7_ANALYZE_TODO;

    }
    else
    {
        /* 判断前三个字符是不是数字，并且根据第一个数字设定响应的返回值 */
        //根据第一个数字设定响应的返回值
        if(*p_data == '1')
            i_ret = APM_L7_ANALYZE_TODO;
        else if(*p_data >= '2' && *p_data <= '5')
            i_ret = APM_L7_ANALYZE_SUCC;
        else
            return APM_L7_ANALYZE_FAIL;
        //判断第二位是否为数字
        if(*(p_data + 1) < '0' || *(p_data + 1) > '9')
            return APM_L7_ANALYZE_FAIL;
        //判断第三位是否为数字
        if(*(p_data + 2) < '0' || *(p_data + 2) > '9')
            return APM_L7_ANALYZE_FAIL;

        //判断是否为session数据
        if(strncasecmp(p_data, "221 ", 4) == 0)
            p_st_private->i_flag_data_type = FRLOGOUT_END;
        else if(strncasecmp(p_data, "530 ", 4) == 0)
            p_st_private->i_flag_data_type = FRLOGIN_FAIL;
        else if(strncasecmp(p_data, "230 ", 4) == 0)
            p_st_private->i_flag_data_type = FRLOGIN_SUCC;

        if(p_st_private->i_flag_data_type == FRLOGIN_START)
            return APM_L7_ANALYZE_TODO;

        if (*(p_data + 3) == ' ')
        {
            /* 取得响应code+命令(name + value) */
            snprintf(arr_code, sizeof(arr_code),"%s",p_data);
            //判断是否为end
            if(p_st_private->p_header_name)
            {
                //不是END返回APM_L7_ANALYZE_FAIL
                if(strcmp(p_st_private->p_header_name,arr_code) != 0)
                {
                    return APM_L7_ANALYZE_FAIL;
                }
            }
            else
            {
                l_response_code = atoi(arr_code);
                if(frreport_body_l7_add_long(p_st_body_data, APM_REPORT_KEY_RESP_CODE, l_response_code) == FR_FAIL)
                    goto ERROR;

                p_response_code_str = (char *)frmalloc (ui_data_len - 1);
                if(p_response_code_str == NULL)
                    goto ERROR;

                snprintf (p_response_code_str, ui_data_len - 1, "%s", p_data);

                if(frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_RESP_CODE_STRING, p_response_code_str) == FR_FAIL)
                    goto ERROR;

                frfree(p_response_code_str);
                p_response_code_str = NULL;
            }

            //关联链路
            if(strcmp(arr_code, "227") == 0)
            {
                //获取value
                ui_len_tmp = (ui_data_len - 3 - 2);
                p_header_value = (char *)frmalloc(ui_len_tmp);
                if(p_header_value == NULL)
                    goto ERROR;

                snprintf(p_header_value,ui_len_tmp,"%s",p_data + 4);

                if(__ftp_get_addr(p_header_value, arr_tmp) == FR_FAIL)
                    goto ERROR;

                if(__ftp_address_parse(arr_tmp, strlen(arr_tmp), &ui_ip, &us_port) == FR_FAIL)
                    goto ERROR;

//                frexpect_add(g_p_apm_context, IPPROTO_TCP, ui_ip, us_port, p_st_conn);

                frfree(p_header_value);
                p_header_value = NULL;
            }
            else if(p_st_private->i_flag_port_cmd == 1 && strcmp(arr_code, "200") == 0)
            {
//                frexpect_add(g_p_apm_context, IPPROTO_TCP, p_st_conn->dst_ip, 20, p_st_conn);
                p_st_private->i_flag_port_cmd = 0;
            }
        }
        else if (*(p_data + 3) == '-')
        {
            /* 如果p_st_private->p_header_name ！= NULL 返回错误 */
            if(p_st_private->p_header_name)
                return APM_L7_ANALYZE_FAIL;
            /* 取得响应code+命令(name + value)，设置p_header_name */
            ui_len_tmp = 3;
            p_st_private->p_header_name = (char *)frmalloc(ui_len_tmp + 1);
            if(p_st_private->p_header_name == NULL)
                goto ERROR;
            snprintf(p_st_private->p_header_name,ui_len_tmp + 1,"%s",p_data);

            l_response_code = atoi(p_st_private->p_header_name);
            if(frreport_body_l7_add_long(p_st_body_data, APM_REPORT_KEY_RESP_CODE, l_response_code) == FR_FAIL)
                goto ERROR;

            p_response_code_str = (char *)frmalloc (ui_data_len - 1);
            if(p_response_code_str == NULL)
                goto ERROR;

            snprintf (p_response_code_str, ui_data_len - 1, "%s", p_data);

            if(frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_RESP_CODE_STRING, p_response_code_str) == FR_FAIL)
                goto ERROR;

            frfree(p_response_code_str);
            p_response_code_str = NULL;

            i_ret = APM_L7_ANALYZE_TODO;
        }
        else
        {
            //destroy 私有信息
            return APM_L7_ANALYZE_FAIL;
        }
    }

    /* 设置value*/
    return i_ret;

ERROR:

    if(p_header_value)
        frfree(p_header_value);

    if(p_response_code_str)
        frfree(p_response_code_str);

    return APM_L7_ANALYZE_FAIL;

}

/*
*   http session 数据上报
*/
FR_STATIC int __ftp_session_report(Frreport_body_data *p_st_body_data, L7session_ftp_private *p_st_private)
{
    if(p_st_body_data == NULL || p_st_private == NULL)
        return FR_FAIL;

    if(frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_SESSION_USERNAME, p_st_private->p_user_name) == FR_FAIL)
        return FR_FAIL;

    if(frreport_body_l7_add_str(p_st_body_data, APM_REPORT_KEY_SESSION_ID, p_st_private->arr_session_id) == FR_FAIL)
        return FR_FAIL;

    if(frreport_body_l7_add_timeval(p_st_body_data, APM_REPORT_KEY_SESSION_LOGIN_TIMESTAMP, &p_st_private->st_login_timestamp) == FR_FAIL)
        return FR_FAIL;

    return FR_SUCC;
}


/*******************************************************************************
*  FUNC     :  ftp的packet解析
*  ARGS     :  p_st_conn                (入力链接信息)
            :  p_st_packet             (入力packet信息)
            :  p_st_hash_report         (保存Frreport_data)
            :  p_st_list_output         (保存Analyz_data_out)
*  RTN      :  APM_L7_ANALYZE_SUCC         成功
*           :  APM_L7_ANALYZE_TODO         数据未结束
*           :  APM_L7_ANALYZE_FAIL         失败
*  NOTE     :
*******************************************************************************/
FR_STATIC int __req_data_analysis(Conntrack *p_st_conn
                                 , Apm_packet *p_st_packet
                                 , Frhash_header *p_st_hash_report
                                 , L7_session *p_st_session)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7session_ftp_private *p_st_private = NULL;
    L4_transaction *p_st_l4_trans = NULL;
    Frreport_data *p_st_report_data = NULL;

    if(p_st_conn == NULL || p_st_packet == NULL
        || p_st_hash_report == NULL || p_st_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_st_private = (L7session_ftp_private *)p_st_session->p_session_private;
    p_st_l4_trans = &(p_st_private->st_l4_trans);

    if( p_st_private->i_flag_data_type == FRLOGIN_FAIL || p_st_private->i_flag_data_type == FRLOGIN_START)
        return APM_L7_ANALYZE_TODO;

    //如果连续的两个request
    if(p_st_private->p_lst_comm)
        __ftp_session_reset((void *)(p_st_private));

    //创建数据链表
    if(p_st_private->p_st_body_data_req == NULL)
    {
        p_st_private->p_st_body_data_req = frreport_body_new_l7(p_st_conn);
        if(p_st_private->p_st_body_data_req == NULL)
            goto ERROR;

        i_ret = frreport_body_l7_add_connInfo(p_st_private->p_st_body_data_req, p_st_conn);
        if(i_ret == FR_FAIL)
            goto ERROR;

        //seq ++
        p_st_private->ul_seq = frct_seq_increase(p_st_conn);
        if(frreport_body_l7_add_ulong(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_ID, p_st_private->ul_seq) == FR_FAIL)
            goto ERROR;

        //ResponseRequired
        if(frreport_body_l7_add_int(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_ISRESPREQUIRED, 1) == FR_FAIL)
            goto ERROR;

        //start time
        if(frreport_body_l7_add_timeval(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_START_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
            goto ERROR;

        //st_request_time_first_byte
        p_st_l4_trans->st_request_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_request_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;

    }

    if(frct_has_master(p_st_conn) == FR_NO)
    {
        //send_time_us
        if(frreport_body_l7_add_long(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_SEND_TIME_US, 0) == FR_FAIL)
            goto ERROR;

        //request bytes
        if(frreport_body_l7_add_long(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_DATA_BYTES, p_st_packet->ui_payload_len) == FR_FAIL)
            goto ERROR;
    }

    //st_request_time
    p_st_l4_trans->st_request_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_request_time.tv_usec = p_st_packet->st_timestamp.tv_usec;

    /* 请求的字节数 */
    p_st_l4_trans->l_request_bytes += p_st_packet->ui_payload_len;

    if(frct_has_master(p_st_conn))
        return APM_L7_ANALYZE_TODO;

    //req解析
    i_ret = __req_parse(p_st_packet->p_payload, p_st_packet->ui_payload_len, p_st_private, p_st_private->p_st_body_data_req, p_st_conn);

    if(i_ret == APM_L7_ANALYZE_SUCC)
    {
        //end time
        if(frreport_body_l7_add_timeval(p_st_private->p_st_body_data_req, APM_REPORT_KEY_REQ_END_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
            goto ERROR;

        if(p_st_private->p_user_name)
        {
            i_ret = __ftp_session_report(p_st_private->p_st_body_data_req, p_st_private);
            if(i_ret == FR_FAIL)
                goto ERROR;
        }

        p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_REQ);
        if(p_st_report_data == NULL)
            goto ERROR;

        //拷贝相关链表
        p_st_private->p_lst_comm = FRREPORT_BODY_L7LIST_CLONE_COMM(p_st_private->p_st_body_data_req);
        if(p_st_private->p_lst_comm == NULL)
            goto ERROR;

        p_st_private->p_lst_req = FRREPORT_BODY_L7LIST_CLONE_REQ(p_st_private->p_st_body_data_req);
        if(p_st_private->p_lst_req == NULL)
            goto ERROR;

        if(frreport_data_add_body(p_st_report_data, p_st_private->p_st_body_data_req) == FR_FAIL)
            goto ERROR;
        p_st_private->p_st_body_data_req = NULL;

        if(frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
            goto ERROR;

        return APM_L7_ANALYZE_SUCC;
    }

ERROR:
    if(p_st_private->p_st_body_data_req)
        frreport_body_free(&p_st_private->p_st_body_data_req);

    if(p_st_report_data)
        frreport_data_free(&p_st_report_data);

    return APM_L7_ANALYZE_FAIL;
}


/*******************************************************************************
*  FUNC     :  ftp的packet解析
*  ARGS     :  p_st_conn                (入力链接信息)
            :  p_st_packet             (入力packet信息)
            :  p_st_hash_report         (保存Frreport_data)
            :  p_st_list_output         (保存Analyz_data_out)
*  RTN      :  APM_L7_ANALYZE_SUCC         成功
*           :  APM_L7_ANALYZE_TODO         数据未结束
*           :  APM_L7_ANALYZE_FAIL         失败
*  NOTE     :
*******************************************************************************/
FR_STATIC int __resp_data_analysis(Conntrack *p_st_conn
                                 , Apm_packet *p_st_packet
                                 , Frhash_header *p_st_hash_report
                                 , L7_session *p_st_session)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7session_ftp_private *p_st_private = NULL;
    L4_transaction *p_st_l4_trans = NULL;
    unsigned long ul_tmp = 0;
    Frreport_data* p_st_report_data = NULL;
    char arr_info[1024];

    if(p_st_conn == NULL || p_st_packet == NULL
        || p_st_hash_report == NULL || p_st_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    p_st_private = (L7session_ftp_private *)p_st_session->p_session_private;
    p_st_l4_trans = &(p_st_private->st_l4_trans);

    if (p_st_l4_trans->st_response_time_first_byte.tv_sec == 0 &&
        p_st_l4_trans->st_response_time_first_byte.tv_usec == 0)
    {
        //创建数据链表
        p_st_private->p_st_body_data_resp = frreport_body_new_l7(p_st_conn);
        if(p_st_private->p_st_body_data_resp == NULL)
            goto ERROR;

        if(p_st_l4_trans->st_request_time_first_byte.tv_sec != 0)
        {
            FRREPORT_BODY_L7LIST_SET_REQ(p_st_private->p_st_body_data_resp, &p_st_private->p_lst_req);
            FRREPORT_BODY_L7LIST_SET_COMM(p_st_private->p_st_body_data_resp, &p_st_private->p_lst_comm);
        }
        else
        {
            i_ret = frreport_body_l7_add_connInfo(p_st_private->p_st_body_data_resp, p_st_conn);
            if(i_ret == FR_FAIL)
                goto ERROR;

            p_st_private->ul_seq = frct_seq_increase(p_st_conn);
            if(frreport_body_l7_add_ulong(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_REQ_ID, p_st_private->ul_seq) == FR_FAIL)
                goto ERROR;
        }
        //start time
        if(frreport_body_l7_add_timeval(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_START_TIMESTAMP, &p_st_packet->st_timestamp) == FR_FAIL)
            goto ERROR;

        p_st_l4_trans->st_response_time_first_byte.tv_sec = p_st_packet->st_timestamp.tv_sec;
        p_st_l4_trans->st_response_time_first_byte.tv_usec = p_st_packet->st_timestamp.tv_usec;

        //首包时间
        if(p_st_l4_trans->st_request_time_first_byte.tv_sec != 0)
        {
            //server time
            p_st_l4_trans->ul_response_time_firstbyte_us = frtime_diff(&(p_st_l4_trans->st_request_time), &(p_st_l4_trans->st_response_time_first_byte));
            if(frreport_body_l7_add_ulong(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_SERVER_TIME_US, p_st_l4_trans->ul_response_time_firstbyte_us) == FR_FAIL)
                goto ERROR;
        }
        else
        {
            //如果不是第一个响应信息  并且没有req数据包  直接返回
            if(strncmp(p_st_packet->p_payload, "220", 3) == 0)
            {
                __ftp_session_reset((void *)(p_st_private));
                //todo
                return APM_L7_ANALYZE_SUCC;
            }

            return APM_L7_ANALYZE_FAIL;
        }
    }
    //st_response_time
    p_st_l4_trans->st_response_time.tv_sec = p_st_packet->st_timestamp.tv_sec;
    p_st_l4_trans->st_response_time.tv_usec = p_st_packet->st_timestamp.tv_usec;
    /* 请求的字节数 */
    p_st_l4_trans->l_response_bytes += p_st_packet->ui_payload_len;

    //文件传输链路 直接返回
    if(frct_has_master(p_st_conn))
        return APM_L7_ANALYZE_TODO;

    //resp解析
    i_ret = __resp_parse(p_st_packet->p_payload, p_st_packet->ui_payload_len, p_st_private, p_st_private->p_st_body_data_resp, p_st_conn);
    if(p_st_private->i_flag_data_type && i_ret == APM_L7_ANALYZE_SUCC)
    {
        if (p_st_private->i_flag_data_type == FRLOGIN_SUCC)
        {
            if (p_st_private->p_user_name != NULL && *p_st_private->p_user_name != '\0')
                snprintf(arr_info, sizeof(arr_info), "%s login", p_st_private->p_user_name);
            else
                snprintf(arr_info, sizeof(arr_info), "login");

            p_st_report_data = frreport_update_create(p_st_conn, APM_REPORT_UPDATE_LOGON, arr_info, &p_st_packet->st_timestamp);

        }
        else if (p_st_private->i_flag_data_type == FRLOGIN_FAIL)
        {
            if (p_st_private->p_user_name != NULL && *p_st_private->p_user_name != '\0')
                snprintf(arr_info, sizeof(arr_info), "%s login reject", p_st_private->p_user_name);
            else
                snprintf(arr_info, sizeof(arr_info), "login reject");

            p_st_report_data = frreport_update_create(p_st_conn, APM_REPORT_UPDATE_LOGON_REJECT, arr_info, &p_st_packet->st_timestamp);

        }
        else if(p_st_private->i_flag_data_type == FRLOGOUT_END)
        {

            if (p_st_private->p_user_name != NULL && *p_st_private->p_user_name != '\0')
                snprintf(arr_info, sizeof(arr_info), "%s logout", p_st_private->p_user_name);
            else
                snprintf(arr_info, sizeof(arr_info), "logout");

            p_st_report_data = frreport_update_create(p_st_conn, APM_REPORT_UPDATE_LOGOUT, arr_info, &p_st_packet->st_timestamp);

        }

        p_st_private->i_flag_data_type = 0;
        if (p_st_report_data)
        {
            if(frreport_send(g_p_apm_context, &p_st_report_data) == FR_FAIL)
            {
                frreport_data_free(&p_st_report_data);
                return APM_L7_ANALYZE_FAIL;
            }
        }
    }

    if(i_ret == APM_L7_ANALYZE_SUCC)
    {
        if(frreport_body_l7_add_long(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_DATA_BYTES, p_st_l4_trans->l_response_bytes) == FR_FAIL)
            goto ERROR;

        //down load time
        ul_tmp = frtime_diff(&(p_st_l4_trans->st_response_time_first_byte), &(p_st_l4_trans->st_response_time));
        if(frreport_body_l7_add_long(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_DOWNLOAD_TIME_US, ul_tmp) == FR_FAIL)
            goto ERROR;

        //end time
        if(frreport_body_l7_add_timeval(p_st_private->p_st_body_data_resp, APM_REPORT_KEY_RESP_END_TIMESTAMP, &p_st_l4_trans->st_response_time) == FR_FAIL)
            goto ERROR;

        p_st_report_data = frreport_data_l7_new(FRREPORT_TYPE_L7DATA_RESP);
        if(p_st_report_data == NULL)
            goto ERROR;

        if(frreport_data_add_body(p_st_report_data, p_st_private->p_st_body_data_resp) == FR_FAIL)
            goto ERROR;
        p_st_private->p_st_body_data_resp = NULL;

        if(frreport_data_hash(p_st_hash_report, p_st_report_data) == FR_FAIL)
            goto ERROR;
        p_st_report_data = NULL;

        //返回值设置
        i_ret = APM_L7_ANALYZE_SET_RESP(APM_L7_ANALYZE_SUCC);
        switch(p_st_private->i_flag_data_type)
        {
            case ( FRLOGIN_SUCC ):
                i_ret = APM_L7_ANALYZE_SET_LOGIN(i_ret);
                break;
            case ( FRLOGIN_FAIL ):
                i_ret = APM_L7_ANALYZE_SET_LOGIN(i_ret);
                return APM_L7_ANALYZE_TODO;
                break;
            case ( FRLOGOUT_END ):
                i_ret = APM_L7_ANALYZE_SET_LOGOUT(i_ret);
                break;
            default:
                break;
        }

        __ftp_session_reset((void *)(p_st_private));

        return i_ret;
    }
    return i_ret;

ERROR:

    if(p_st_report_data)
        frreport_data_free(&p_st_report_data);

    if(p_st_private->p_st_body_data_resp)
        frreport_body_free(&p_st_private->p_st_body_data_resp);

    return APM_L7_ANALYZE_FAIL;
}
/*******************************************************************************
*  FUNC     :  ftp的packet解析
*  ARGS     :  p_st_conn                (入力链接信息)
            :  p_st_packet             (入力packet信息)
            :  p_st_hash_report         (保存Frreport_data)
*  RTN      :  APM_L7_ANALYZE_SUCC         成功
*           :  APM_L7_ANALYZE_TODO         数据未结束
*           :  APM_L7_ANALYZE_FAIL         失败
*  NOTE     :
*******************************************************************************/
int ftp_analysis(Conntrack *p_st_conn
                  , Apm_packet *p_st_packet
                  , Frhash_header *p_st_hash_report)
{
    int i_ret = APM_L7_ANALYZE_SUCC;
    L7_session *p_st_session = NULL;


    if(p_st_conn == NULL || p_st_packet == NULL
        || p_st_hash_report == NULL)
        return APM_L7_ANALYZE_FAIL;

    /* 到Conntrack中取得session信息 */
    p_st_session = frct_get_session(p_st_conn);
    if (p_st_session == NULL)
        return APM_L7_ANALYZE_FAIL;

    //fin syn 包  销毁私有数据
    if(p_st_packet->em_analyz_cmd == FRANALYZ_CMD_FIN || p_st_packet->em_analyz_cmd == FRANALYZ_CMD_SYN)
    {
        //文件上传数据上报
        ftp_session_destroy((void *)(p_st_session->p_session_private));
        p_st_session->p_session_private = NULL;
        return APM_L7_ANALYZE_SUCC;
    }

    //p_session_private   分配内存
    if(p_st_session->p_session_private == NULL)
    {
        p_st_session->p_session_private = __ftp_private_create();
        //内存分配失败
        if(p_st_session->p_session_private == NULL)
            return APM_L7_ANALYZE_FAIL;
    }

    //request
    if(p_st_packet->i_direction == FR_DIRECT_CLIENT2SRV)
    {
        i_ret = __req_data_analysis(p_st_conn,p_st_packet,p_st_hash_report,p_st_session);
        if(i_ret == APM_L7_ANALYZE_FAIL)
            goto ERROR;

        return i_ret;
    }
    else//response
    {
        i_ret = __resp_data_analysis(p_st_conn,p_st_packet,p_st_hash_report, p_st_session);
        if (i_ret == APM_L7_ANALYZE_FAIL)
            goto ERROR;

        return i_ret;
    }

ERROR:
    if(p_st_session->p_session_private)
        ftp_session_destroy(p_st_session->p_session_private);
    p_st_session->p_session_private = NULL;
    return APM_L7_ANALYZE_FAIL;

}

/*******************************************************************************
*  FUNC     :  私有信息销毁
*  ARGS     :  p_private_session(ftp的私有session数据)
*  RTN      :  FR_SUCC
*  NOTE     :
*******************************************************************************/
int ftp_session_destroy(void *p_private_session)
{

    L7session_ftp_private *p_st_private = (L7session_ftp_private *)p_private_session;
    if(p_st_private)
    {
        if(p_st_private->p_st_body_data_req)
            frreport_body_free(&p_st_private->p_st_body_data_req);

        if(p_st_private->p_st_body_data_resp)
            frreport_body_free(&p_st_private->p_st_body_data_resp);

        if(p_st_private->p_lst_req)
            frreport_body_l7list_free(&p_st_private->p_lst_req);

        if(p_st_private->p_lst_comm)
            frreport_body_l7list_free(&p_st_private->p_lst_comm);

        if(p_st_private->p_header_name)
            frfree(p_st_private->p_header_name);

        if(p_st_private->p_user_name)
            frfree(p_st_private->p_user_name);

        frfree(p_st_private);
    }
    return FR_SUCC;
}


